/*
 * Copyright (C), 2015-2019
 * FileName: BaseAttributeInfo
 * Author:   lizhao
 * Date:     2019-02-11 19:18
 * Description: 通用实现类
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lizhaoblog.jjvm.classfile.attribute;

import com.lizhaoblog.jjvm.classfile.ClassReader;
import com.lizhaoblog.jjvm.classfile.constantpool.ConstantPool;

/**
 * 〈一句话功能简述〉<br>
 * 〈通用实现类〉
 *
 * @author lizhao
 * @date 2019-02-11 19:18
 * @since 1.0.0
 */
public class BaseAttributeInfo {

    /**
     * 读取属性表数组
     *
     * @param reader       ClassReader
     * @param constantPool 常量池
     * @return 属性表 数组
     */
    public static AttributeInfo[] readAttributes(ClassReader reader, ConstantPool constantPool) {
        int attributesCount = reader.nextU2ToInt();
        AttributeInfo[] attributes = new AttributeInfo[attributesCount];

        for (int i = 0; i < attributesCount; i++) {
            attributes[i] = readAttribute(reader, constantPool);
        }

        return attributes;
    }

    /**
     * 读取byte，并且创建一个属性表
     *
     * @param reader       ClassReader
     * @param constantPool 常量池
     * @return 属性表
     */
    private static AttributeInfo readAttribute(ClassReader reader, ConstantPool constantPool) {
        int attrNameIndex = reader.nextU2ToInt();
        String attrName = constantPool.getUtfStringByIndex(attrNameIndex);
        long attrLen = reader.nextU4ToInt();
        AttributeInfo attributeInfo = newAttributeInfo(attrName, attrLen, constantPool);
        attributeInfo.readInfo(reader);
        return attributeInfo;
    }


    /**
     * 创建一个AttributeInfo
     *
     * @param attrName     名字
     * @param attrLen      该属性表所占长度
     * @param constantPool 常量池
     * @return 属性表
     */
    private static AttributeInfo newAttributeInfo(String attrName, long attrLen, ConstantPool constantPool) {
        switch (attrName) {
            //method属性
            case "Code"://方法体
                return new CodeAttribute(constantPool);
            //field属性
            case "ConstantValue"://常量表达式的值  存常量池索引
                return new ConstantValueAttribute();
            //method属性
            case "Exceptions"://变长属性，记录方法抛出的异常表
                return new ExceptionsAttribute();
            //以下3是调试信息 不一定要 使用javac编译器编译Java程序时，默认会在class文件中生成 这些信息
            //  method属性的Code属性的属性
            case "LineNumberTable"://方法行号
                return new LineNumberTableAttribute();
            //  method属性的Code属性的属性
            case "LocalVariableTable"://方法局部变量
                return new LocalVariableTableAttribute();
            //class属性
            case "SourceFile"://源文件名 如 XXX.java
                return new SourceFileAttribute(constantPool);
            //最简单的两种属性，仅起标记作用，不包含任何数据。
            //ClassFile、field_info和method_info都可以用
            case "Synthetic"://为了支持嵌套类和嵌套接口
                return new SyntheticAttribute();
            case "Deprecated"://废弃标记
                return new DeprecatedAttribute();
            //不支持
            default:
                return new UnparsedAttribute(attrName, (int) attrLen);
        }
    }

}
